<template>
  <!--渲染表单-->
  <el-form v-if="mode === 'PC'" ref="form" class="process-form" label-position="top" :rules="rules" :model="_value" size="default">
    <div :class="{ readonly: isReadonly(item) }" v-show="showItem(item)" v-for="(item, index) in forms" :key="item.name + index">
      <el-form-item v-if="item.name !== 'SpanLayout' && item.name !== 'Description'" :prop="item.id" :label="item.title">
        <form-design-render :readonly="isReadonly(item)" :ref="setItemRef" v-model="_value[item.id]" :formData="_value" :mode="mode" :config="item"/>
      </el-form-item>
      <form-design-render :ref="setItemRef" :readonly="isReadonly(item)" v-else v-model="_value" :formData="_value" :mode="mode" :config="item"/>
    </div>
  </el-form>
  <div v-else class="process-form">
    <div :class="{ readonly: isReadonly(item) }" v-show="showItem(item)" v-for="(item, index) in forms" :key="item.name + index">
      <form-item v-if="item.name !== 'SpanLayout' && item.name !== 'Description'" :model="_value" :rule="rules[item.id]" :ref="setItemRef" :prop="item.id" :label="item.title">
        <form-design-render :readonly="isReadonly(item)" :formData="_value" :ref="item.id + '_item'" v-model="_value[item.id]" :mode="mode" :config="item"/>
      </form-item>
      <form-design-render :ref="setItemRef" :readonly="isReadonly(item)" :formData="_value" v-else v-model="_value" :mode="mode" :config="item"/>
    </div>
  </div>
</template>

<script>
import { Field, Form } from 'vant'
import FormItem from '/@/views/setting/workflow/common/FormItem.vue'
import FormDesignRender from '/@/views/setting/workflow/common/FormDesignRender.vue'
import { ValueType } from '/@/views/setting/workflow/config/ComponentsConfigExport'
import { CompareFuncs } from "/@/views/setting/workflow/components/compare/CompareOptions";
import { computed, reactive, toRefs, watch, ref } from 'vue'
import { isNotEmpty } from '/@/utils/utils'

const VForm = Form
export default {
    name: 'FormRender',
    components: { FormItem, FormDesignRender, VForm, Field },
    props: {
        forms: {
            type: Array,
            default: () => {
                return []
            },
        },
        config: {
            type: Object,
            default: () => {
                return {
                ruleType: "SIMPLE",
                rules: [],
                }
            }
        },
        process: {
            type: Object,
            default: () => {
                return {}
            },
        },
        //当前节点，用来联动表单权限
        currentNode: {
            type: String,
            default: null,
        },
        modelValue: {
            type: Object,
            default: () => {
                return {}
            },
        },
        mode: {
            type: String,
            default: 'PC',
        },
    },
    emits: ['update:modelValue'],
    setup(props, context) {
        const { modelValue, forms, config } = toRefs(props)
        let refs = []
        const form = ref()
        const state = reactive({
            formRules: {},
            //缓存下原始权限设置
            formPermHis: {},
            compareFunc: {},
            //缓存旧值
            oldFormData: {},
            //缓存所有用到的条件字段
            conditionFields: new Set(),
            execute: null,
            field: {}
        })
        const setItemRef = el => {
            if (el) {
                refs.push(el)
            }
        }
        const _value = computed({
            get: () => {
                return modelValue.value
            },
            set: val => {
                context.emit('update:modelValue', val)
            }
        })
        const rules = computed(() => {
            let rules = {}
            loadFormConfig(forms.value, rules)
            return rules
        })
        const formItemMap = computed(() => {
            const map = new Map()
            loadFormItemMap(forms.value, map)
            return map
        })
        const showItem = (item) => {
            return ((!(isReadonly(item)
                && isBlank(_value.value[item.id]))) || item.name === 'SpanLayout')
                && item.perm !== 'H'
        }
        const isBlank = (val) => {
            return (
                !isNotEmpty(val) ||
                (val instanceof String && val.trim() === '') ||
                (Array.isArray(val) && val.length === 0)
            )
        }
        const isReadonly = (item) => {
            return item.perm === 'R'
        }
        const validate = (call) => {
            let success = true
            console.log(this.rules)
            if (this.mode === 'PC') {
                form.value.validate((valid) => {
                    success = valid
                    if (valid) {
                        //校验成功再校验内部
                        for (let i = 0; i < this.forms.length; i++) {
                            if (this.forms[i].name === 'TableList') {
                                // TO DO 这里是没获取的ref
                                let formRef = this.$refs[this.forms[i].id]
                                if (formRef && Array.isArray(formRef) && formRef.length > 0) {
                                    formRef[0].validate((subValid) => {
                                        success = subValid
                                    })
                                    if (!success) {
                                        break
                                    }
                                }
                            }
                        }
                    }
                    call(success)
                })
            } else {
                this.forms.forEach((form) => {
                    let formRef = this.$refs[form.id]
                    if (formRef && Array.isArray(formRef) && formRef.length > 0) {
                        formRef[0].validate((subValid) => {
                            console.log('校验' + form.title, form.id, subValid)
                            if (!subValid) {
                                success = false
                            }
                        })
                        if (form.name === 'TableList') {
                            // TO DO 这里是没获取的ref
                            //扫描明细表项
                            this.$refs[form.id + '_item'][0].validate((subValid) => {
                                if (!subValid) {
                                    success = false
                                }
                            })
                        }
                    }
                })
                call(success)
            }
        }
        const loadFormItemMap = (forms, map) => {
            forms.forEach(item => {
                if (item.name === 'TableList') {
                    map.set(item.id, item)
                    loadFormItemMap(item.props.columns, map)
                } else if (item.name === 'SpanLayout') {
                    loadFormItemMap(item.props.items, map)
                } else {
                    map.set(item.id, item)
                }
            })
        }
        const loadFormConfig = (forms, rules) => {
            forms.forEach((item) => {
                if (item.name === 'SpanLayout') {
                    loadFormConfig(item.props.items, rules)
                } else {
                    _value.value[item.id] = modelValue.value[item.id]
                    if (item.props.required && showItem(item)) {
                        rules[item.id] = [
                            {
                                type: ValueType.getValidType(item.valueType),
                                required: true,
                                message: `请完成${item.title}`,
                                trigger: 'blur',
                            },
                        ]
                    }
                }
            })
        }
        //解析表单联动规则
        const parserRule = (cdRule) => {
            const condition = cdRule.condition
            //在这里可以实现一个算法，按条件层级去解析，不需要解析所有条件，先不实现
            if (cdRule.children.length > 0) {
                for (let i = 0; i < cdRule.children.length; i++) {
                const result = parserRule(cdRule.children[i])
                if (cdRule.logic){
                    //如果是且关系，有一个为假就是假
                    if (!result){
                        return false
                    }
                }else {
                    //如果是或关系，有一个为真就是真
                    if (result){
                        return true
                    }
                }
                }
                //遍历完了返回最终结果
                return cdRule.logic
            } else {
                //解析条件
                try {
                    return compare(condition)
                }catch (e) {
                    return false
                }
            }
        }
        const doActions = async (actions) => {
            (actions || []).forEach(action => {
                //执行预设的动作
                switch (action.type){
                    case 'SHOW': action.targets.forEach(tg => showField(tg)); break;
                    case 'HIDE': action.targets.forEach(tg => hideField(tg)); break;
                    case 'DISABLE': action.targets.forEach(tg => disableField(tg)); break;
                    case 'UPDATE': action.targets.forEach(tg => updateField(tg, action.value)); break;
                    case 'ENABLE': action.targets.forEach(tg => enableField(tg, action.value)); break;
                }
            })
        }
        const analyseFormRule = () => {
            if (config.value.ruleType === 'SIMPLE'){
                analyseRules()
            }else {
                analyseJsRules()
            }
        }
        const analyseJsRules = async () => {
            if (!(state.execute instanceof Function)) {
                state.execute = new Function('formData', 'formMap',
                `${config.value.ruleJs || 'function doChange(){}'}\r\n doChange(formData, formMap);`)
            }
            state.execute(_value.value, formItemMap)
        }
        const analyseRules = async () => {
            (config.value.rules || []).forEach((rule, i) => {
                //解析表单联动条件
                const result = parserRule(rule.condition)
                console.log(`解析规则 ${(i + 1)}: ${result}`)
                doActions(result ? rule.action.with : rule.action.other)
            })
        }
        const compare = (condition) => {
            //要判断组件类型，再取其值
            const source = _value.value[condition.field]
            //动态调用函数
            let compareType = null
            switch (condition.fieldType) {
                case 'AmountInput':
                case 'NumberInput':
                case 'Score':
                case 'CalcFormula':
                    compareType = 'numCompare';
                break;
                case 'TextInput':
                case 'TextareaInput':
                case 'SelectInput':
                case 'Location':
                case 'Provinces':
                    compareType = 'strCompare'
                break;
                case 'MultipleSelect':
                    compareType = 'strArrCompare';
                break;
                case 'DateTime':
                    compareType = 'timeCompare';
                break;
                case 'DateTimeRange':
                    compareType = 'timeArrCompare';
                break;
                case 'DeptPicker':
                case 'UserPicker':
                    compareType = 'orgCompare';
                break;
            }
            return CompareFuncs[compareType][condition.compare](source,
                condition.fixed ? condition.compareVal
                : _value.value[condition.compareVal[0]])
        }
        const isRequired = (item) => {
            return rules.value[item.id] !== undefined
        }
        const hideField = (id) => {
            const field = formItemMap.value.get(id)
            if (field){
                state.field.perm = 'H'
                // this.$set(field, 'perm', 'H')
            }
        }
        const showField = (id) => {
            const field = formItemMap.value.get(id)
            if (field){
                state.field.perm = state.formPermHis[id] || 'E'
                // this.$set(field, 'perm', this.formPermHis[id] || 'E')
            }
        }
        const disableField = (id) => {
            const field = formItemMap.value.get(id)
            if (field) {
                state.field.perm = 'R'
                // this.$set(field, 'perm', 'R')
            }
        }
        const enableField = (id) => {
            const field = formItemMap.value.get(id)
            if (field) {
                state.field.perm = 'E'
                // this.$set(field, 'perm', 'E')
            }
        }
        const updateField = (id, val) => {
            const field = formItemMap.value.get(id)
            if (field) {
                _value.value[id] = val
            }
        }
        watch(
            () => modelValue.value,
            () => {
                if (config.value){
                    if (Object.keys(state.formPermHis).length === 0){
                        formItemMap.value.forEach(item => {
                            state.formPermHis[item.id] = item.perm
                        })
                    }
                    analyseFormRule()
                }
            },
            {
                deep: true,
            }      
        )
        return {
            ...toRefs(state),
            _value,
            rules,
            formItemMap,
            showItem,
            setItemRef,
            validate,
            loadFormItemMap,
            loadFormConfig,
            doActions,
            analyseFormRule,
            analyseJsRules,
            analyseRules,
            compare,
            isRequired,
            hideField,
            showField,
            disableField,
            enableField,
            updateField,
            form,
            isReadonly
        }
    }
}
</script>

<style lang="scss" scoped>
.process-form {
    :deep(.el-form-item__label) {
        height: 30px;
        line-height: 30px;
        padding: 0 0;
    }

    :deep(.van-cell) {
        padding: 10px 0;
        font-size: 1.2rem;
    }
    :deep(.el-form-item:last-of-type){
        margin-bottom: 18px !important;
    }
}

:deep(.el-form-item__label){
  margin-bottom: 0 !important;
}

:deep(.readonly) {
  font-size: 16px;
  .el-form-item {
    margin-bottom: 10px;

    .el-form-item__label::before {
      display: none;
    }

    .el-form-item__content {
      padding-left: 5px;
      line-height: 30px;
    }
  }

  .m-form-item {
    padding: 10px 5px;
    margin-bottom: 0;

    .m-form-item_title {
      font-size: 16px;

      .title-required {
        display: none;
      }
    }

    .m-form-item_content {
      padding-left: 4px;
    }
  }
}
</style>